package com.dream52.pms.main;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 代码生成工具 V1.0
 * 详情请阅读博客：https://www.cnblogs.com/huanzi-qch/p/14927738.html
 */
@Controller
public class AutoGenerator {
    /**
     * 程序自动设置
     */
    private String tableName;//表名
    private String tableComment;//表注释


    /**
     * 数据连接相关，需要手动设置
     */
    private static final String URL = "jdbc:mysql://192.168.0.250:3308/pms_1?serverTimezone=GMT%2B8&characterEncoding=utf-8";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "123456";
    private static final String DRIVER_CLASSNAME = "com.mysql.cj.jdbc.Driver";

    /**
     * 基础路径，需要手动设置
     */
    private String basePackage = "cn\\baseadmin\\";//根包位置
    private String filePackage = basePackage + "sys\\";//文件所在包位置
    private String prefix = "sys";//前缀

    /**
     * 构造参数，设置表名
     */
//    private AutoGenerator(String tableName) {
//        //设置表名
//        this.tableName = tableName;
//
//        //文件所在包位置
//        filePackage = filePackage + StringUtil.camelCaseName(tableName).toLowerCase() + "\\" ;
//
//        //拼接完整最终位置 System.getProperty("user.dir") 获取的是项目所在路径，如果我们是子项目，则需要添加一层路径
//        filePath = System.getProperty("user.dir") + "\\src\\main\\java\\" + filePackage;
//    }


    /**
     * Provider
     */
    private String createProvider(List<TableInfo> tableInfos) {

        String code = "";
        //遍历属性
        code +=
                "package " + filePackage.replaceAll("\\\\", ".") + "sql; <br>" +

                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Provider {<br>";
        code += " public String getSql(String sql) {<br><br>" +

                "return sql;<br>" +
                "}<br> ";
        code += ("}<br>");
        return code;
    }


    /**
     * Mapper
     */
    private String createMapper(List<TableInfo> tableInfos) {

        String code = "";
        //遍历属性
        code +=
                "package " + filePackage.replaceAll("\\\\", ".") + "mapper; <br>" +
                        " <br>" +
                        "import " + basePackage.replaceAll("\\\\", ".") + "base.MyMapper; <br>" +
                        "import " + filePackage.replaceAll("\\\\", ".") + "entity." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "; <br>" +
                        "import " + filePackage.replaceAll("\\\\", ".") + "sql." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Provider;<br>" +
                        " <br>" +
                        "public interface " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Mapper extends MyMapper&lt" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "&gt {";
        code += " <br>";
        code += ("}<br>");
        return code;
    }


    /**
     * Entity
     */
    private String createEntity(List<TableInfo> tableInfos) {

        //拼接文件内容
        String code = new String();
        code +=
                "package " + filePackage.replaceAll("\\\\", ".") + "entity;<br>" +
                        "<br>" +
                        "import lombok.Data;<br>" +
                        "import javax.persistence.*;<br>" +
                        "import java.io.Serializable;<br>" +
                        "import java.util.Date;<br>" +
                        "import org.springframework.format.annotation.DateTimeFormat;<br>" +
                        "import com.alibaba.fastjson.annotation.JSONField;<br>" +
                        "<br>" +
                        "@Entity<br>" +
                        "@Table(name = \"" + tableName + "\")<br>" +
                        "@Data<br>" +
                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + " implements Serializable {<br>"
        ;
        code += " // " + tableComment + "<br><br>";
        code += " private static final long serialVersionUID = 1L;<br>";
        //遍历设置属性
        for (TableInfo tableInfo : tableInfos) {
            //主键
            if ("PRI".equals(tableInfo.getColumnKey())) {
                code += "    @Id<br>";
            }
            //自增
            if ("auto_increment".equals(tableInfo.getExtra())) {
                code += "    @GeneratedValue(strategy= GenerationType.IDENTITY)<br>";
            }
            code += "@Column(name = \"" + StringUtil.camelCaseName(tableInfo.getColumnName()) + "\")<br>";

            if (StringUtil.isDate(tableInfo.getDataType())) {
                code += " @DateTimeFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")<br>";
                code += " @JSONField(format = \"yyyy-MM-dd HH:mm:ss\")<br>";
            }

            code += "    private " + StringUtil.typeMapping(tableInfo.getDataType()) + (" ") + StringUtil.camelCaseName(tableInfo.getColumnName()) + (";//") + tableInfo.getColumnComment() + "<br>";
        }
        code += "}";

        return code;

    }


    /**
     * 创建service类
     */
    private String createService(List<TableInfo> tableInfos) {

        String code = "";
        //遍历属性

        code +=
                "package " + filePackage.replaceAll("\\\\", ".") + "service; <br>" +
                        " <br>" +
                        "import " + basePackage.replaceAll("\\\\", ".") + "base.MyService; <br>" +
                        "import " + filePackage.replaceAll("\\\\", ".") + "entity." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "; <br>" +

                        " <br>" +
                        "public interface " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service extends MyService&lt" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "&gt {"
        ;
        code += " <br>";
        code += ("}<br>");
        return code;

    }

    /**
     * 创建serviceImpl类
     */
    private String createServiceImpl(List<TableInfo> tableInfos) {

        String code = "";
        //遍历属性

        code += "package " + filePackage.replaceAll("\\\\", ".") + "service.impl; <br>" +
                " <br>" +
                "import " + basePackage.replaceAll("\\\\", ".") + "base.MyServiceImpl; <br>" +
                "import " + filePackage.replaceAll("\\\\", ".") + "entity." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "; <br>" +
                "import " + filePackage.replaceAll("\\\\", ".") + "service." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service; <br>" +
                "import org.springframework.stereotype.Service; <br>" +
                "import org.springframework.transaction.annotation.Transactional;<br>"+

                " <br>" +
                "@Service <br>" +
                "@Transactional <br>" +
                "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "ServiceImpl extends MyServiceImpl&lt" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "&gt implements " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service{";
        code += " <br>";
        code += ("}<br>");

        return code;
    }


    /**
     * 创建controller类
     */
    private String createController(List<TableInfo> tableInfos) {

        String code = "";

        code +=
                "package " + filePackage.replaceAll("\\\\", ".") + "controller; <br>" +
                        " <br>" +
                        "import " + basePackage.replaceAll("\\\\", ".") + "base.BaseController; <br>" +
                        "import " + filePackage.replaceAll("\\\\", ".") + "entity." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "; <br>" +
                        "import " + filePackage.replaceAll("\\\\", ".") + "service." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service; <br>" +
                        "import "+basePackage.replaceAll("\\\\", ".")+"sys.entity.SysUser; <br>" +
                        "import org.springframework.beans.factory.annotation.Autowired; <br>" +
                        "import com.github.pagehelper.PageInfo;<br>" +
                        "import org.springframework.web.bind.annotation.*; <br>" +
                        "import java.util.List;<br>" +
                        " <br>" +
                        "@RestController <br>" +
                        "@RequestMapping(\"/" + this.prefix + "/" + StringUtil.camelCaseName(tableName) + "\") <br>" +
                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Controller extends BaseController {"
        ;
        code += " <br>";
        code += "" +
                "    @Autowired <br>" +
                "    private " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service " + StringUtil.camelCaseName(tableName) + "Service; <br>";


        code += " @GetMapping(\"/list\") <br>" +
                "@ResponseBody <br>" +
                "public String get" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "List(Integer pageNo,Integer pageSize) throws Exception{ <br>" +
                "SysUser user = this.getUserSession(); <br>" +
                "String where = \"1 = 1\"; <br>" +
                "if(user != null){ <br>" +
                "if(null==pageNo||pageNo.toString().length() < 1){<br>" +
                "List<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "> " + StringUtil.camelCaseName(tableName) + "List = this." + StringUtil.camelCaseName(tableName) + "Service.getListByWhere(where,\"id ASC\"); <br>" +
                "this.result.put(\"" + StringUtil.camelCaseName(tableName) + "List\", " + StringUtil.camelCaseName(tableName) + "List); <br>" +


                "}else{<br>" +
                "   PageInfo<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "> pageInfo = this." + StringUtil.camelCaseName(tableName) + "Service.getPageByWhere(where,pageNo, this.pageSize,\"id ASC\"); <br>" +
                "   this.result.put(\"pageInfo\", pageInfo); <br>" +
                "}<br>" +
                "return this.toPageJson(this.SUCCESS_CODE); <br>" +
                "} <br>" +
                "return this.toPageJson(this.ERROR_CODE,\"请先登录\"); <br>" +
                "}<br>";


        code += " @GetMapping(\"/get\") <br>" +
                " @ResponseBody <br>" +
                " public String get" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "(Integer id) throws Exception{ <br>" +
                "  SysUser user = this.getUserSession(); <br>" +
                "  " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + " b = new " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "(); <br>" +
                "   if(user != null ){ <br>" +
                "    if(id!=null && id>0){ <br>" +
                "     b = this." + StringUtil.camelCaseName(tableName) + "Service.getById(id); <br>" +
                "    } <br>" +
                "   this.result.put(\"bean\", b); <br>" +
                "   return this.toPageJson(this.SUCCESS_CODE); <br>" +
                "  } <br>" +
                "  return this.toPageJson(this.ERROR_CODE,\"请先登录\"); <br>" +
                " }<br>";


        code += " @PostMapping(\"/save\") <br>" +
                " @ResponseBody <br>" +
                " public String save" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "(" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + " entity) throws Exception{ <br>" +
                "  SysUser user = this.getUserSession(); <br>" +
                "  if (entity.getId() == null){ <br>" +
                "   this." + StringUtil.camelCaseName(tableName) + "Service.save(entity); <br>" +
                "  }else { <br>" +
                "   this." + StringUtil.camelCaseName(tableName) + "Service.update(entity); <br>" +
                "  } <br>" +
                "  return this.toPageJson(this.SUCCESS_CODE); <br>" +
                " }<br>";

        code += " @PostMapping(\"/del\") <br>" +
                " @ResponseBody <br>" +
                " public String del" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "( Integer id) throws Exception{ <br>" +
                "  SysUser user = this.getUserSession(); <br>" +
                "  if (id != null&&id.toString().length()>0){ <br>" +
                "   this." + StringUtil.camelCaseName(tableName) + "Service.deleteById(id); <br>" +
                "  } <br>" +
                "  return this.toPageJson(this.SUCCESS_CODE); <br>" +
                " }<br>";

        code += "}<br>";

        return code;
    }


    /**
     * 字符串处理工具类
     */
    private static class StringUtil {
        /**
         * 数据库类型->JAVA类型
         *
         * @param dbType 数据库类型
         * @return JAVA类型
         */
        private static String typeMapping(String dbType) {
            String javaType;
            if ("int|integer".contains(dbType)) {
                javaType = "Integer";
            } else if ("float|double|real".contains(dbType)) {
                javaType = "Double";
            } else if ("date|time|datetime|timestamp".contains(dbType)) {
                javaType = "Date";
            } else if ("decimal".contains(dbType)) {
                javaType = "BigDecimal";
            } else {
                javaType = "String";
            }
            return javaType;
        }

        private static Boolean isDate(String dbType) {

            Boolean is = false;
            if ("date|time|datetime|timestamp".contains(dbType)) {
                is = true;
            }
            return is;
        }

        /**
         * 驼峰转换为下划线
         */
        private static String underscoreName(String camelCaseName) {
            StringBuilder result = new StringBuilder(1024);
            if (camelCaseName != null && camelCaseName.length() > 0) {
                result.append(camelCaseName.substring(0, 1).toLowerCase());
                for (int i = 1; i < camelCaseName.length(); i++) {
                    char ch = camelCaseName.charAt(i);
                    if (Character.isUpperCase(ch)) {
                        result.append("_");
                        result.append(Character.toLowerCase(ch));
                    } else {
                        result.append(ch);
                    }
                }
            }
            return result.toString();
        }

        /**
         * 首字母大写
         */
        private static String captureName(String name) {
            char[] cs = name.toCharArray();
            cs[0] -= 32;
            return String.valueOf(cs);

        }

        /**
         * 下划线转换为驼峰
         */
        private static String camelCaseName(String underscoreName) {
            StringBuilder result = new StringBuilder(1024);
            if (underscoreName != null && underscoreName.length() > 0) {
                boolean flag = false;
                for (int i = 0; i < underscoreName.length(); i++) {
                    char ch = underscoreName.charAt(i);
                    if ("_".charAt(0) == ch) {
                        flag = true;
                    } else {
                        if (flag) {
                            result.append(Character.toUpperCase(ch));
                            flag = false;
                        } else {
                            result.append(ch);
                        }
                    }
                }
            }
            return result.toString();
        }
    }

    /**
     * JDBC连接数据库工具类
     */
    private static class DBConnectionUtil {

        static {
            // 1、加载驱动
            try {
                Class.forName(DRIVER_CLASSNAME);
            } catch (ClassNotFoundException e) {

                e.printStackTrace();
            }
        }

        /**
         * 返回一个Connection连接
         */
        static Connection getConnection() {
            Connection conn = null;
            // 2、连接数据库
            try {
                conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            } catch (SQLException e) {

                e.printStackTrace();
            }
            return conn;
        }

        /**
         * 关闭Connection，Statement连接
         */
        public static void close(Connection conn, Statement stmt) {
            try {
                conn.close();
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        /**
         * 关闭Connection，Statement，ResultSet连接
         */
        public static void close(Connection conn, Statement stmt, ResultSet rs) {
            try {
                close(conn, stmt);
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 表结构信息实体类
     */
    private class TableInfo {
        private String columnName;//字段名
        private String dataType;//字段类型
        private String columnComment;//字段注释
        private String columnKey;//主键
        private String extra;//主键类型

        public String getColumnName() {
            return columnName;
        }

        public void setColumnName(String columnName) {
            this.columnName = columnName;
        }

        public String getDataType() {
            return dataType;
        }

        public void setDataType(String dataType) {
            this.dataType = dataType;
        }

        public String getColumnComment() {
            return columnComment;
        }

        public void setColumnComment(String columnComment) {
            this.columnComment = columnComment;
        }

        public String getColumnKey() {
            return columnKey;
        }

        public void setColumnKey(String columnKey) {
            this.columnKey = columnKey;
        }

        public String getExtra() {
            return extra;
        }

        public void setExtra(String extra) {
            this.extra = extra;
        }
    }

    /**
     * 获取表结构信息
     * 目前仅支持mysql
     */
    private List<TableInfo> getTableInfo(String tableName) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        ArrayList<TableInfo> list = new ArrayList<>();
        try {
            conn = DBConnectionUtil.getConnection();

            //表字段信息
            String sql = "select column_name,data_type,column_comment,column_key,extra from information_schema.columns where table_schema = (select database()) and table_name=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, tableName);
            rs = ps.executeQuery();
            while (rs.next()) {
                TableInfo tableInfo = new TableInfo();
                //列名，全部转为小写
                tableInfo.setColumnName(rs.getString("column_name"));
                //列类型
                tableInfo.setDataType(rs.getString("data_type"));
                //列注释
                tableInfo.setColumnComment(rs.getString("column_comment"));
                //主键
                tableInfo.setColumnKey(rs.getString("column_key"));
                //主键类型
                tableInfo.setExtra(rs.getString("extra"));
                list.add(tableInfo);
            }

            //表注释
            sql = "select table_comment from information_schema.tables where table_schema = (select database()) and table_name=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, tableName);
            rs = ps.executeQuery();
            while (rs.next()) {
                //表注释
                tableComment = rs.getString("table_comment");
            }
        } catch (SQLException e) {

            e.printStackTrace();
        } finally {
            if (rs != null) {
                DBConnectionUtil.close(conn, ps, rs);
            }
        }
        return list;
    }

    @ResponseBody
    @GetMapping("/autoCode")
    public String autoCode(String tableName, String type) {
        this.tableName = tableName;
        this.basePackage = "com\\dream52\\pms\\";
        this.prefix = tableName.split("_")[0];
        this.filePackage = this.basePackage + this.prefix + "\\";//文件所在包位置
        List<TableInfo> tableInfo = getTableInfo(tableName);

        if (type.equals("Entity")) {
            return createEntity(tableInfo);
        }
        if (type.equals("Service")) {
            return createService(tableInfo);
        }
        if (type.equals("mpl")) {
            return createServiceImpl(tableInfo);
        }
        if (type.equals("Controller")) {
            return createController(tableInfo);
        }
        if (type.equals("Provider")) {
            return createProvider(tableInfo);
        }
        if (type.equals("Mapper")) {
            return createMapper(tableInfo);
        }
        return createServiceImpl(tableInfo);

    }


}
